#if !defined(___DCT_C)
#define ___DCT_C
#include "std.h"


static N1 _zz2[64],_zz1[64]=
{ 0, 1, 5, 6,14,15,27,28,
  2, 4, 7,13,16,26,29,42,
  3, 8,12,17,25,30,41,43,
  9,11,18,24,31,40,44,53,
 10,19,23,32,39,45,52,54,
 20,22,33,38,46,51,55,60,
 21,34,37,47,50,56,59,61,
 35,36,48,49,57,58,62,63,
};
N1 *zz1=_zz1,*zz2=_zz2;
static RI _tt[64];
RI *tt=_tt;


I4 DctInit(xx)
{ // ZigZag 1,2
  { I1 x1=0,y1=0,j1=0,up=1;
    for (;j1<64;++j1)
    { zz1[y1*8+x1]=j1;
      if (up) { ++x1; --y1; }
      else { --x1; ++y1; }
      if (up)
      { if (x1>7) { x1=7; y1+=2; up=0; }
        if (y1<0) { y1=0; up=0; }
      } else
      { if (y1>7) { y1=7; x1+=2; up=1; }
        if (x1<0) { x1=0; up=1; }
      }
    }
    for (x1=0;x1<64;++x1)
      zz2[zz1[x1]]=x1;
    DEB0("[........] (ZigZag):\n");
    for (j1=y1=0;y1<8;++y1)
    { DEB0("[........] [");
      for (x1=0;x1<8;++x1,++j1)
        DEB1(" %02i",zz1[j1]);
      DEB0("]    [");
      for (j1-=8,x1=0;x1<8;++x1,++j1)
        DEB1(" %02i",zz2[j1]);
      DEB0("]\n");
    }
  }

  // DCT const
#if !defined(___ROPT)
#define ROPT(x) (x)
#else
#define ROPT(x) ((I4)RoundR4((x)*0x10000ul))
#endif
  { R4 j1,j2; N2 i0=0;
    R4 r1=1.0/sqrt(2.0);
    for (j1=0.5;j1<8;++j1)
    { tt[i0++]=ROPT(0.5*r1);
      for (j2=1.0;j2<8;++j2)
        tt[i0++]=ROPT(0.5*(R4)cos
        (M_PI/8.0*j1*j2));
    }
    DEB0("[........] (DCT):\n");
    for (i0=0;i0<64;++i0)
    { if ((i0&7)==0)
        DEB0("[........] [");
      DEB1("  " _ri,tt[i0]);
      if ((i0&7)==7)
        DEB0("]\n");
    }
  }
#undef ROPT

  return (0);
}

I4 ZigZag(N1 *zz,RI *dd1,RI *dd2)
{ N2 i1; for (i1=0;i1<64;++i1)
    dd2[*(zz++)]=*(dd1++);
  return (0);
}

I4 LevelShift1(N1 *dd1,RI *dd2)
{ I2 ii; N2 i1;
  for (i1=0;i1<64;++i1)
  { ii=((I2)(N2)*(dd1++))-128;
    *(dd2++)=(RI)ii;
  }
  return (0);
}
I4 LevelShift2(RI *dd1,N1 *dd2)
{ RI rr; N2 i1;
  for (i1=0;i1<64;++i1)
  { rr=RoundRI(*(dd1++))+128;
    if (rr<0) rr=0; else
    if (rr>255) rr=255;
    *(dd2++)=(N1)rr;
  }
  return (0);
}

I4 Quant1(N2 *q1,RI *dd1,I2 *dd2)
{ N2 i1;
  for (i1=0;i1<64;++i1)
    *(dd2++)=(I2)RoundR4(*(dd1++)/((R4)*(q1++)));
  return (0);
}
I4 Quant2(N2 *q1,I2 *dd1,RI *dd2)
{ N2 i1;
  for (i1=0;i1<64;++i1)
    *(dd2++)=((RI)*(dd1++))*((RI)*(q1++));
  return (0);
}

I4 DCT1(RI *tt,RI *dd1,RI *dd2)
{ N2 u,v;
  for (v=0;v<8;++v)
    for (u=0;u<8;++u)
      *(dd2++)=DCT1x(tt,dd1,u,v);
  return (0);
}
I4 DCT2(RI *tt,RI *dd1,RI *dd2)
{ N2 x,y;
  for (y=0;y<8;++y)
    for (x=0;x<8;++x)
      *(dd2++)=DCT2x(tt,dd1,x,y);
  return (0);
}
#if !defined(___ROPT)
#define ROPT(x) (x)
#else
#define ROPT(x) ((x)>>16)
#endif
R4 DCT1x(RI *tt,RI *dd,N1 u,N1 v)
{ N2 x,y; RI rr,*t0,*t1,*t2;
  rr=0; t1=tt+u; t2=tt+v;
  //for (y=0;y<8;++y)
  //  for (x=0;x<8;++x)
  //    rr+=*(dd++)*tt[x*8+u]*tt[y*8+v];
  for (t0=t1,y=0;y<8;++y,t2+=8)
    for (t1=t0,x=0;x<8;++x,t1+=8)
      rr+=*(dd++)*ROPT((*t1)*(*t2));
  return (ROPT(rr));
}
R4 DCT2x(RI *tt,RI *dd,N1 x,N1 y)
{ N2 u,v; RI rr,*t0,*t1,*t2;
  rr=0; t1=tt+x*8; t2=tt+y*8;
  //for (v=0;v<8;++v)
  //  for (u=0;u<8;++u)
  //    rr+=*(dd++)*tt[x*8+u]*tt[y*8+v];
  for (t0=t1,v=0;v<8;++v,++t2)
    for (t1=t0,u=0;u<8;++u,++t1)
      rr+=*(dd++)*ROPT((*t1)*(*t2));
  return (ROPT(rr));
}
#undef ROPT

xx Color1(N1 *cr,N1 *cg,N1 *cb)
{
#if !defined(___ROPT)
  R4 c1=RoundR4(0.299*(*cr)+0.587*(*cg)+0.114*(*cb));
  R4 c2=RoundR4(-0.1687*(*cr)-0.3313*(*cg)+0.5*(*cb)+128);
  R4 c3=RoundR4(0.5*(*cr)-0.4187*(*cg)-0.0813*(*cb)+128);
  if (c1<0) c1=0; else
  if (c1>255) c1=255;
  if (c2<0) c2=0; else
  if (c2>255) c2=255;
  if (c3<0) c3=0; else
  if (c3>255) c3=255;
  *cr=(N1)c1; *cg=(N1)c2; *cb=(N1)c3;
#else
  I4 r1=(I4)(N2)*cr;
  I4 r2=(I4)(N2)*cg;
  I4 r3=(I4)(N2)*cb;
  I4 c1=((19595l*r1+38470l*r2+7471l*r3)>>16);
  I4 c2=((-11056l*r1-21712l*r2+32768l*r3)>>16)+128;
  I4 c3=((32768l*r1-27440l*r2-5328l*r3)>>16)+128;
  if (c1<0) c1=0; else
  if (c1>255) c1=255;
  if (c2<0) c2=0; else
  if (c2>255) c2=255;
  if (c3<0) c3=0; else
  if (c3>255) c3=255;
  *cr=(N1)c1; *cg=(N1)c2; *cb=(N1)c3;
#endif
}
xx Color2(N1 *c1,N1 *c2,N1 *c3)
{
#if !defined(___ROPT)
  R4 r1=(R4)(N2)(*c1);
  R4 r2=(R4)(N2)(*c2)-128;
  R4 r3=(R4)(N2)(*c3)-128;
  R4 cr=RoundR4(r1+1.402*r3);
  R4 cg=RoundR4(r1-0.34414*r2-0.71414*r3);
  R4 cb=RoundR4(r1+1.772*r2);
  if (cr<0) cr=0; else
  if (cr>255) cr=255;
  if (cg<0) cg=0; else
  if (cg>255) cg=255;
  if (cb<0) cb=0; else
  if (cb>255) cb=255;
  *c1=(N1)cr; *c2=(N1)cg; *c3=(N1)cb;
#else
  I4 r1=(I4)(N2)(*c1);
  I4 r2=(I4)(N2)(*c2)-128;
  I4 r3=(I4)(N2)(*c3)-128;
  I4 cr=r1+((91881l*r3)>>16);
  I4 cg=r1-((22554l*r2)>>16)-((46802l*r3)>>16);
  I4 cb=r1+((116130l*r2)>>16);
  if (cr<0) cr=0; else
  if (cr>255) cr=255;
  if (cg<0) cg=0; else
  if (cg>255) cg=255;
  if (cb<0) cb=0; else
  if (cb>255) cb=255;
  *c1=(N1)cr; *c2=(N1)cg; *c3=(N1)cb;
#endif
}


#endif
